package com.yuantu.judiciary.config;

import com.yuantu.judiciary.security.filter.JwtAuthenticationTokenFilter;
import com.yuantu.judiciary.security.handler.MyLogoutHandler;
import com.yuantu.judiciary.security.handler.MyLogoutSuccessHandler;
import com.yuantu.judiciary.security.handler.RestAccessDeniedHandler;
import com.yuantu.judiciary.security.handler.RestAuthenticationEntryPoint;
import com.yuantu.judiciary.utils.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * 安全配置
 *
 * @author syw
 * @since 2023-06-14
 **/
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig {

    private static final int ENCODE_STRENGTH = 4;

    /**
     * 用于knife4j
     */
    public static final String[] KNIFE4J = {
            "/doc.html",
            "/webjars/*",
            "/swagger-resources",
            "/v2/*",
            "/v3/*"
    };

    /**
     * 静态资源白名单
     */
    public static final String[] STATIC_RESOURCE_WHITE_LIST = {
            // 静态资源文件
            "/",
            "/**/**/*.js",
            "/**/*.css",
            "/**/*.html",
            "/**/*.svg",
            "/**/*.pdf",
            "/**/*.jpg",
            "/**/*.png",
            "/**/*.gif",
            "/**/*.ico",
            // 排除字体格式后缀
            "/**/*.ttf",
            "/**/*.woff",
            "/**/*.woff2",
            // 排除Druid、Swagger、H2
            "/druid/**",
            "/*/api-docs",
            "/webjars/**",
            "/swagger-resources/**",
            "/h2-console/**/**",
            "/doc.html",
            "/**"
    };

//    @Bean
//    public WebSecurityCustomizer webSecurityCustomizer() {
//        return (web) -> web.ignoring().regexMatchers(KNIFE4J);
//    }

    /**
     * 密码明文加密方式配置
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(ENCODE_STRENGTH);
    }

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    /**
     * 配置跨源访问(CORS)
     */
    @Bean
    protected CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

    @Bean
    public JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter() {
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 配置添加自定义认证数据源，替换过滤器
     */
    @Bean
    protected SecurityFilterChain filerChain(HttpSecurity http) throws Exception {
        http    // 基于 token，不需要 csrf
                .csrf().disable()
                // 禁用默认登录页
                .formLogin().disable()
                // 禁用默认登出页
                .logout().disable()
                // 基于 token，不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 下面开始设置权限
                .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
//                      // 静态资源放行
                        .antMatchers(KNIFE4J).permitAll()
                        .antMatchers(STATIC_RESOURCE_WHITE_LIST).permitAll()
                        // 接口放行
                        .antMatchers(JwtUtil.getWhiteList()).permitAll()
                        .antMatchers("/user/login/**", "/open/ali/**", "/**", "/profile/files/**").permitAll()
                        // 除上面外的所有请求全部需要鉴权认证
                        .anyRequest().authenticated()
                )
                // 认证与授权失败处理类
                .exceptionHandling()
                .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                .accessDeniedHandler(new RestAccessDeniedHandler())
                .and()
                // 拦截器
                .addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class)
                // 退出登录
                .logout()
                .logoutUrl("/user/logout")
                .addLogoutHandler(new MyLogoutHandler())
                .logoutSuccessHandler(new MyLogoutSuccessHandler())
                .and()
                // 跨域
                .cors().configurationSource(corsConfigurationSource());
        return http.build();
    }

}
